package arsmodeller.part;

import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.Label;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.jface.viewers.TextCellEditor;

import arsmodeller.editpolicies.ThingComponentEditPolicy;
import arsmodeller.editpolicies.ThingDirectEditPolicy;
import arsmodeller.editpolicies.ThingGraphicalNodeEditPolicy;
import arsmodeller.figure.ThingFigure;
import arsmodeller.model.Link;
import arsmodeller.model.Thing;

import java.util.List;

public abstract class ThingEditPart extends AbstractGraphicalEditPart implements
		NodeEditPart {

	private ThingAdapter adapter;

	@Override
	protected void createEditPolicies() {
		installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE,
				new ThingDirectEditPolicy());
		installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE,
				new ThingGraphicalNodeEditPolicy());
		installEditPolicy(EditPolicy.COMPONENT_ROLE,
				new ThingComponentEditPolicy());
	}

	@Override
	protected List<Link> getModelSourceConnections() {
		Thing model = (Thing) getModel();
		return model.getOutgoingLinks();
	}

	@Override
	protected List<Link> getModelTargetConnections() {
		Thing model = (Thing) getModel();
		return model.getIncomingLinks();
	}

	@Override
	protected void refreshVisuals() {
		ThingFigure figure = (ThingFigure) getFigure();
		Thing model = (Thing) getModel();
		ObjectProcessDiagramEditPart parent = (ObjectProcessDiagramEditPart) getParent();

		figure.getNameLabel().setText(model.getName());
		parent.setLayoutConstraint(this, figure, model.getConstraints());
	}

	public ConnectionAnchor getSourceConnectionAnchor(
			ConnectionEditPart connection) {
		return ((ThingFigure) getFigure()).getConnectionAnchor();
	}

	public ConnectionAnchor getTargetConnectionAnchor(
			ConnectionEditPart connection) {
		return ((ThingFigure) getFigure()).getConnectionAnchor();
	}

	@Override
	public ConnectionAnchor getSourceConnectionAnchor(Request request) {
		return ((ThingFigure) getFigure()).getConnectionAnchor();
	}

	@Override
	public ConnectionAnchor getTargetConnectionAnchor(Request request) {
		return ((ThingFigure) getFigure()).getConnectionAnchor();
	}

	@Override
	public void activate() {
		if (!isActive()) {
			((Thing) getModel()).eAdapters().add(adapter);
		}
		super.activate();
	}

	@Override
	public void deactivate() {
		if (isActive()) {
			((Thing) getModel()).eAdapters().remove(adapter);
		}

		super.deactivate();
	}

	@Override
	public void performRequest(Request req) {
		if (req.getType() == RequestConstants.REQ_DIRECT_EDIT) {
			performDirectEditing();
		}
	}

	private void performDirectEditing() {
		Label label = ((ThingFigure) getFigure()).getNameLabel();
		ThingDirectEditManager manager = new ThingDirectEditManager(this,
				TextCellEditor.class, new ThingCellEditorLocator(label), label);
		manager.show();
	}

	public class ThingAdapter implements Adapter {

		// Adapter interface
		@Override
		public void notifyChanged(Notification notification) {
			refreshVisuals();
			refreshSourceConnections();
			refreshTargetConnections();
		}

		@Override
		public Notifier getTarget() {
			return (Thing) getModel();
		}

		@Override
		public void setTarget(Notifier newTarget) {
			// Do nothing.
		}

		@Override
		public boolean isAdapterForType(Object type) {
			return type.equals(Thing.class);
		}
	}
}
